﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

namespace JQuery
{
    public static partial class Extensions
    {
        public static bool IsNullOrEmpty(this string obj)
        {
            return String.IsNullOrEmpty(obj);
        }

        public static bool IsNotNullOrEmpty(this string obj)
        {
            return obj.IsNullOrEmpty() == false;
        }

        public static string Regex(this string obj, string pattern, string replacement)
        {
            return new Regex(pattern, RegexOptions.ECMAScript | RegexOptions.IgnoreCase).Replace(obj, replacement);
        }

        public static bool Eq(this string obj, string expected)
        {
            return obj.Equals(expected, StringComparison.CurrentCultureIgnoreCase);
        }

        public static bool NotEq(this string obj, string expected)
        {
            return !obj.Eq(expected);
        }

        public static string ToJSON(this object oObject)
        {
            return JsonConvert.SerializeObject(oObject, new StringEnumConverter());
        }

        public static string Join(this string obj, string seperator, params string[] strings)
        {
            return String.Join(seperator, new string[] { obj }.Union(strings).ToArray());
        }

        public static string EncodeTo64(this string pSrc)
        {
            byte[] oBytes = Encoding.Unicode.GetBytes(pSrc);

            return Convert.ToBase64String(oBytes);
        }

        public static string DecodeFrom64(this string pSrc)
        {
            byte[] oBytes = Convert.FromBase64String(pSrc);

            return Encoding.Unicode.GetString(oBytes);
        }

        public static string ToJSProper(this string obj)
        {
           char[] arrayObj = obj.ToCharArray();

           if (!char.IsLower(arrayObj[0]))
           {
               arrayObj[0] = char.ToLower(arrayObj[0]);
           }

           return new string(arrayObj);
        }

        private static Regex tokenReplacements = new Regex(@"\[\$(?<property>[^\$]*?)\$\]|\[\$(?<method>[^\$]*?)\((?:(?<params>.*?)(?:,|(?=\))))*?\)\$\]", 
            RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);

        /// <summary>
        /// replace any token encapsulated by brackets with the value from the corresponding property of the source object
        /// </summary>
        public static string ApplyTokenReplacements(this string text, object source)
        {
            if (source == null)
            {
                return text;
            }

            Type oClass = source.GetType();

            foreach (Match oMatch in tokenReplacements.Matches(text))
            {
                string
                    property = oMatch.GetPropertyName(),
                    method = oMatch.GetMethodName(),
                    value = String.Empty;

                string[]
                    parameters = oMatch.GetMethodParameterNames();

                if (property.IsNotNullOrEmpty())
                {   /// the token replacement is a property name
                    value =  oClass.GetProperty(property).GetValue(source, null).ToString();

                    text = text.Replace(String.Format("[${0}$]", property), value);
                }
                else if (method.IsNotNullOrEmpty())
                {   /// the token replacement is a method name with 0 or more parameters
                    /// TODO:: Finish the token replace for parameters
                }
            }
            return text;
        }

        private static string GetPropertyName(this Match oMatch)
        {
            return oMatch.Groups["property"].Value;
        }

        private static string GetMethodName(this Match oMatch)
        {
            return oMatch.Groups["method"].Value;
        }

        private static string[] GetMethodParameterNames(this Match oMatch)
        {
            if (!oMatch.Groups["params"].Success)
                return new string[] { };    // if failed return an empty array

            CaptureCollection oCollection = oMatch.Groups["params"].Captures;

            string[] paramArray = new string[oCollection.Count];

            for (int i = 0; i < oCollection.Count; i++)
            {
                paramArray[i] = oCollection[i].Value;
            }

            return paramArray;
        }
    }
}
